///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef _SceneNode_H__
#define _SceneNode_H__

#include "OgrePrerequisites.h"

#include "OgreNode.h"
#include "OgreIteratorWrappers.h"
#include "math/axisAlignedBox.h"

namespace Ogre {

	// forward decl
	struct VisibleObjectsBoundsInfo;

	
	
	
    class _OgreExport SceneNode : public Node
    {
    public:
        typedef HashMap<String, MovableObject*> ObjectMap;
        typedef MapIterator<ObjectMap> ObjectIterator;
		typedef ConstMapIterator<ObjectMap> ConstObjectIterator;

    protected:
        ObjectMap mObjectsByName;

		/// Pointer to a Wire Bounding Box for this Node
		WireBoundingBox *mWireBoundingBox;
		/// Flag that determines if the bounding box of the node should be displayed
		bool mShowBoundingBox;
        bool mHideBoundingBox;

        /// SceneManager which created this node
        SceneManager* mCreator;

        /// World-Axis aligned bounding box, updated only through _update
        AxisAlignedBox mWorldAABB;

        
        void updateFromParentImpl(void) const;

        
        Node* createChildImpl(void);

        
        Node* createChildImpl(const String& name);

		
		void setParent(Node* parent);

		
		virtual void setInSceneGraph(bool inGraph);

        /// Whether to yaw around a fixed axis.
        bool mYawFixed;
        /// Fixed axis to yaw around
        Vector3 mYawFixedAxis;

        /// Auto tracking target
        SceneNode* mAutoTrackTarget;
        /// Tracking offset for fine tuning
        Vector3 mAutoTrackOffset;
        /// Local 'normal' direction vector
        Vector3 mAutoTrackLocalDirection;
		/// Is this node a current part of the scene graph?
		bool mIsInSceneGraph;
    public:
        
        SceneNode(SceneManager* creator);
        
        SceneNode(SceneManager* creator, const String& name);
        ~SceneNode();

        
        virtual void attachObject(MovableObject* obj);

        
        virtual unsigned short numAttachedObjects(void) const;

        
        virtual MovableObject* getAttachedObject(unsigned short index);

        
        virtual MovableObject* getAttachedObject(const String& name);

        
        virtual MovableObject* detachObject(unsigned short index);
        
        virtual void detachObject(MovableObject* obj);

        
        virtual MovableObject* detachObject(const String& name);

        
        virtual void detachAllObjects(void);

		
		virtual bool isInSceneGraph(void) const { return mIsInSceneGraph; }

		
		virtual void _notifyRootNode(void) { mIsInSceneGraph = true; }
			

        
        virtual void _update(bool updateChildren, bool parentHasChanged);

		
		virtual void _updateBounds(void);

        
		virtual void _findVisibleObjects(Camera* cam, RenderQueue* queue, 
			VisibleObjectsBoundsInfo* visibleBounds, 
            bool includeChildren = true, bool displayNodes = false, bool onlyShadowCasters = false);

        
        virtual const AxisAlignedBox& _getWorldAABB(void) const;

        
        virtual ObjectIterator getAttachedObjectIterator(void);
        
		virtual ConstObjectIterator getAttachedObjectIterator(void) const;

        
        SceneManager* getCreator(void) const { return mCreator; }

        
        virtual void removeAndDestroyChild(const String& name);

        
        virtual void removeAndDestroyChild(unsigned short index);

        
        virtual void removeAndDestroyAllChildren(void);

        
		virtual void showBoundingBox(bool bShow);

        
		virtual void hideBoundingBox(bool bHide);

        
		virtual void _addBoundingBoxToQueue(RenderQueue* queue);

        
		virtual bool getShowBoundingBox() const;

        
        virtual SceneNode* createChildSceneNode(
            const Vector3& translate = Vector3::ZERO, 
            const Quaternion& rotate = Quaternion::IDENTITY );

        
        virtual SceneNode* createChildSceneNode(const String& name, const Vector3& translate = Vector3::ZERO, const Quaternion& rotate = Quaternion::IDENTITY);

        
        virtual void findLights(LightList& destList, Real radius, uint32 lightMask = 0xFFFFFFFF) const;

        
        virtual void setFixedYawAxis( bool useFixed, const Vector3& fixedAxis = Vector3::UNIT_Y );

		
		virtual void yaw(const Radian& angle, TransformSpace relativeTo = TS_LOCAL);
        
        virtual void setDirection(Real x, Real y, Real z, 
            TransformSpace relativeTo = TS_LOCAL, 
            const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z);

        
        virtual void setDirection(const Vector3& vec, TransformSpace relativeTo = TS_LOCAL, 
            const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z);
        
        virtual void lookAt( const Vector3& targetPoint, TransformSpace relativeTo,
            const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z);
        
        virtual void setAutoTracking(bool enabled, SceneNode* const target = 0, 
            const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z,
            const Vector3& offset = Vector3::ZERO);
		
        virtual SceneNode* getAutoTrackTarget(void) { return mAutoTrackTarget; }
		
		virtual const Vector3& getAutoTrackOffset(void) { return mAutoTrackOffset; }
		
		virtual const Vector3& getAutoTrackLocalDirection(void) { return mAutoTrackLocalDirection; }
		
        void _autoTrack(void);
        
        SceneNode* getParentSceneNode(void) const;
        
        virtual void setVisible(bool visible, bool cascade = true);
        
        virtual void flipVisibility(bool cascade = true);

        
        virtual void setDebugDisplayEnabled(bool enabled, bool cascade = true);

		/// As Node::getDebugRenderable, except scaling is automatically determined
//		virtual DebugRenderable* getDebugRenderable();




    };
	
	


}// namespace

#endif
